// Copyright (C) 2009, Bronislaw (Bronek) Kozicki
//
// Use, modification, and distribution is subject to MIT License
// For details see http://opensource.org/licenses/mit-license.php
//
// NO WARRANTY OF ANY KIND, EITHER IMPLIED OR EXPRESS, ETC. ETC.
//

#include "single_ptr.hpp"

#include <string>
#include <cstdio>


class Test
{
	Test(const Test&); // noncopyable & nonassignable
	Test& operator=(const Test&);

public:
	const std::string str;
	Test(std::string::size_type i, char t, const std::string& before, const std::string& after, char t2)
		: str(std::string(i, t) + before + after + t2 + std::string(i, t))
	{}
};

class IGulp
{
	IGulp(const IGulp&); // noncopyable & nonassignable
	IGulp& operator=(const IGulp&);

protected:
	IGulp() {}

public:
	virtual const std::string& how() const = 0;
	virtual ~IGulp() {}
};

class Gulp : public IGulp
{
	explicit Gulp(const std::string& t) : str(t) {}
	friend class Throat;
	const std::string str;

public:
	virtual const std::string& how() const {return str;}
};

class Throat
{
	Throat(const Throat&); // noncopyable & nonassignable
	Throat& operator=(const Throat&);

	std::string str;

public:
	explicit Throat(const char* t) : str(t) {}

	// acquire and release functions are used by single_ptr
	const IGulp* acquire() const {return new Gulp(str);}
	void release(const IGulp* p) const {delete p;}
};

void f()
{
	util::single_ptr<IGulp> g;		// will only increment ...
	std::printf("%s\n", g->how().c_str());
} // ... and then decrement reference counter of single_ptr<IGulp>

int main(int argc, char** argv)
{
	util::single_ptr<double>::init(); 
	util::single_ptr<double> d;		// will use default (zero) constructor
	std::printf("%f\n", *d);

	util::single_ptr<int>::init(42); 
	util::single_ptr<int> i;		// will use copy constructor
	std::printf("%i\n", *i);

	util::single_ptr<Test>::init(3, '-', std::string("hello "), std::string("world"), '!');
	util::single_ptr<Test> t;		// will use "long" constructor
	std::printf("%s\n", t->str.c_str());

	const Throat throat("gulp!");
	util::single_ptr<IGulp>::init(&throat); 
	util::single_ptr<IGulp> g;		// will use factory
	f();
	std::printf("%s\n", g->how().c_str());
} // all objects owned by util::single_ptr created above are destroyed at this point


